package cn.cdu.medical.service.impl;

import cn.cdu.medical.dto.PrescriptionDTO;
import cn.cdu.medical.entity.Medicine;
import cn.cdu.medical.entity.Prescription;
import cn.cdu.medical.entity.PrescriptionDetail;
import cn.cdu.medical.mapper.PrescriptionDetailMapper;
import cn.cdu.medical.mapper.PrescriptionMapper;
import cn.cdu.medical.service.IMedicineService;
import cn.cdu.medical.service.IPrescriptionService;
import cn.cdu.medical.vo.PrescriptionVO;
import cn.cdu.medical.vo.PrescriptionDetailVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Calendar;
import java.util.ArrayList;

@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class PrescriptionServiceImpl extends ServiceImpl<PrescriptionMapper, Prescription> implements IPrescriptionService {

    private final IMedicineService medicineService;
    private final PrescriptionDetailMapper prescriptionDetailMapper;

    @Override
    public String createPrescription(PrescriptionDTO prescriptionDTO) {
        log.info("创建处方, prescriptionDTO: {}", prescriptionDTO);
        Prescription prescription = new Prescription();
        prescription.setId(generateId());
        prescription.setMedicalRecordId(prescriptionDTO.getMedicalRecordId());
        prescription.setPatientId(prescriptionDTO.getPatientId());
        prescription.setDoctorId(prescriptionDTO.getDoctorId());
        prescription.setStatus("0");
        prescription.setPrescriptionNo(generatePrescriptionNo());
        prescription.setPrescriptionType(prescriptionDTO.getPrescriptionType());
        prescription.setInstructions(prescriptionDTO.getInstructions());
        prescription.setNotes(prescriptionDTO.getNotes());
        // 设置默认有效期开始时间为当前时间
        prescription.setValidityStartTime(prescriptionDTO.getValidityStartTime() != null ? prescriptionDTO.getValidityStartTime() : new Date());
        // 设置默认有效期结束时间为当前时间加14天
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, 14);
        prescription.setValidityEndTime(prescriptionDTO.getValidityEndTime() != null ? prescriptionDTO.getValidityEndTime() : calendar.getTime());
        prescription.setCreateTime(new Date());
        prescription.setUpdateTime(new Date());
        prescription.setCreateBy(prescriptionDTO.getDoctorId());
        prescription.setUpdateBy(prescriptionDTO.getDoctorId());
        prescription.setDelFlag(0);
        save(prescription);

        // 保存处方明细
        List<PrescriptionDetail> details = prescriptionDTO.getMedicines().stream()
            .map(detailDTO -> {
                PrescriptionDetail detail = new PrescriptionDetail();
                detail.setId(generateId());
                detail.setPrescriptionId(prescription.getId());
                detail.setMedicineId(detailDTO.getMedicineId());
                detail.setMedicineName(detailDTO.getMedicineName());
                detail.setSpecification(detailDTO.getSpecification());
                detail.setUnit(detailDTO.getUnit());
                detail.setAmount(detailDTO.getAmount());
                detail.setUsageMethod(detailDTO.getUsageMethod());
                detail.setFrequency(detailDTO.getFrequency());
                detail.setDays(detailDTO.getDays());
                detail.setSingleDose(detailDTO.getSingleDose());
                detail.setTotalDose(detailDTO.getTotalDose());
                detail.setNotes(detailDTO.getNotes());
                detail.setCreateTime(new Date());
                detail.setUpdateTime(new Date());
                detail.setCreateBy(prescriptionDTO.getDoctorId());
                detail.setUpdateBy(prescriptionDTO.getDoctorId());
                return detail;
            })
            .collect(Collectors.toList());

        prescriptionDetailMapper.insertBatchDetail(details);
        return prescription.getId();
    }

    @Override
    public PrescriptionVO getPrescriptionDetail(String id) {
        log.info("获取处方详情, id: {}", id);
        return baseMapper.selectPrescriptionById(id);
    }

    @Override
    public IPage<PrescriptionVO> getPrescriptionPage(Page<PrescriptionVO> page, String patientId, String doctorId, Integer status) {
        log.info("分页查询处方列表, page: {}, patientId: {}, doctorId: {}, status: {}", page, patientId, doctorId, status);
        String statusStr = status != null ? String.valueOf(status) : null;
        return baseMapper.selectPrescriptionPage(page, patientId, doctorId, statusStr);
    }

    @Override
    public boolean updatePrescriptionStatus(String id, Integer status) {
        log.info("更新处方状态, id: {}, status: {}", id, status);
        Prescription prescription = getById(id);
        if (prescription == null) {
            log.error("处方不存在, id: {}", id);
            return false;
        }
        prescription.setStatus(String.valueOf(status));
        prescription.setUpdateTime(new Date());
        return updateById(prescription);
    }

    @Override
    public boolean invalidatePrescription(String id) {
        log.info("作废处方, id: {}", id);
        return updatePrescriptionStatus(id, -1);
    }

    @Override
    public PrescriptionVO getPrescriptionById(String id) {
        log.info("根据ID查询处方详情, id: {}", id);
        return baseMapper.selectPrescriptionById(id);
    }

    @Override
    public String addPrescription(Prescription prescription) {
        log.info("新增处方, prescription: {}", prescription);
        prescription.setId(generateId());
        prescription.setPrescriptionNo(generatePrescriptionNo());
        prescription.setCreateTime(new Date());
        prescription.setUpdateTime(new Date());
        if (prescription.getStatus() == null) {
            prescription.setStatus("0");
        }
        save(prescription);
        return prescription.getId();
    }

    @Override
    public List<PrescriptionVO> getPrescriptionsByMedicalRecordId(String medicalRecordId) {
        log.info("根据病历ID查询处方列表, medicalRecordId: {}", medicalRecordId);
        try {
            // 构建查询条件
            QueryWrapper<Prescription> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("medical_record_id", medicalRecordId)
                       .eq("del_flag", 0)
                       .orderByDesc("create_time");
            
            // 查询处方列表
            List<Prescription> prescriptions = list(queryWrapper);
            log.info("查询到处方数量: {}", prescriptions.size());
            
            // 转换为VO对象
            List<PrescriptionVO> result = prescriptions.stream()
                    .map(prescription -> {
                        PrescriptionVO vo = new PrescriptionVO();
                        BeanUtils.copyProperties(prescription, vo);
                        try {
                            // 查询处方明细
                            List<PrescriptionDetailVO> details = prescriptionDetailMapper.selectDetailsByPrescriptionId(prescription.getId());
                            log.info("处方[{}]的药品数量: {}", prescription.getId(), details.size());
                            
                            // 将处方明细转换为药品列表
                            List<Medicine> medicines = details.stream()
                                .map(detail -> {
                                    Medicine medicine = new Medicine();
                                    medicine.setId(detail.getMedicineId());
                                    medicine.setName(detail.getMedicineName());
                                    medicine.setSpecification(detail.getSpecification());
                                    medicine.setUnit(detail.getUnit());
                                    return medicine;
                                })
                                .collect(Collectors.toList());
                            
                            vo.setMedicines(medicines);
                        } catch (Exception e) {
                            log.error("查询处方明细失败, prescriptionId: {}", prescription.getId(), e);
                            vo.setMedicines(new ArrayList<>());
                        }
                        return vo;
                    })
                    .collect(Collectors.toList());
            
            log.info("处理完成, 返回处方VO数量: {}", result.size());
            return result;
        } catch (Exception e) {
            log.error("查询处方列表失败, medicalRecordId: {}", medicalRecordId, e);
            return new ArrayList<>();
        }
    }

    @Override
    public boolean updatePrescription(PrescriptionDTO prescriptionDTO) {
        log.info("修改处方, prescriptionDTO: {}", prescriptionDTO);
        try {
            // 查询原处方信息
            Prescription prescription = getById(prescriptionDTO.getId());
            if (prescription == null) {
                log.error("处方不存在, id: {}", prescriptionDTO.getId());
                return false;
            }

            // 检查处方状态
            if (!"0".equals(prescription.getStatus())) {
                log.error("处方状态不允许修改, status: {}", prescription.getStatus());
                return false;
            }

            // 更新处方基本信息
            prescription.setPrescriptionType(prescriptionDTO.getPrescriptionType());
            prescription.setInstructions(prescriptionDTO.getInstructions());
            prescription.setNotes(prescriptionDTO.getNotes());
            prescription.setValidityStartTime(prescriptionDTO.getValidityStartTime());
            prescription.setValidityEndTime(prescriptionDTO.getValidityEndTime());
            prescription.setUpdateTime(new Date());
            prescription.setUpdateBy(prescriptionDTO.getDoctorId());
            
            // 更新处方
            updateById(prescription);

            // 删除原有处方明细
            QueryWrapper<PrescriptionDetail> wrapper = new QueryWrapper<>();
            wrapper.eq("prescription_id", prescription.getId());
            prescriptionDetailMapper.delete(wrapper);

            // 保存新的处方明细
            List<PrescriptionDetail> details = prescriptionDTO.getMedicines().stream()
                .map(detailDTO -> {
                    PrescriptionDetail detail = new PrescriptionDetail();
                    detail.setId(generateId());
                    detail.setPrescriptionId(prescription.getId());
                    detail.setMedicineId(detailDTO.getMedicineId());
                    detail.setMedicineName(detailDTO.getMedicineName());
                    detail.setSpecification(detailDTO.getSpecification());
                    detail.setUnit(detailDTO.getUnit());
                    detail.setAmount(detailDTO.getAmount());
                    detail.setUsageMethod(detailDTO.getUsageMethod());
                    detail.setFrequency(detailDTO.getFrequency());
                    detail.setDays(detailDTO.getDays());
                    detail.setSingleDose(detailDTO.getSingleDose());
                    detail.setTotalDose(detailDTO.getTotalDose());
                    detail.setNotes(detailDTO.getNotes());
                    detail.setCreateTime(new Date());
                    detail.setUpdateTime(new Date());
                    detail.setCreateBy(prescriptionDTO.getDoctorId());
                    detail.setUpdateBy(prescriptionDTO.getDoctorId());
                    return detail;
                })
                .collect(Collectors.toList());

            prescriptionDetailMapper.insertBatchDetail(details);
            return true;
        } catch (Exception e) {
            log.error("修改处方失败", e);
            return false;
        }
    }

    private String generatePrescriptionNo() {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        String random = String.format("%04d", (int) (Math.random() * 10000));
        return "CF" + timestamp + random;
    }

    private Date convertToDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    private String generateId() {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        String random = String.format("%04d", (int) (Math.random() * 10000));
        return "P" + timestamp + random;
    }
}